using System;
using System.IO;
using System.Text;
using System.Drawing;
using System.Reflection;
using System.Data.SqlClient;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Open.Data.Persistence;


namespace Open.Data.Persistence.Testing
{
    [TestClass]
    public class EntityTests
    {
        //Initialise test class
        [ClassInitialize()]
        public static void ClassInitialize(TestContext testContext)
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Person person = new Person();
            person.Id = 1;
            person.Insert(command);
        }

        //Simple entity tests
        [TestMethod]
        public void EntityLoadPerson()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Person person = new Person();
            person.Id = 1;
            person.Select(command);

            Assert.IsTrue(person.Id == 1, "Incorrect person record loaded.");
        }

        [TestMethod, ExpectedException(typeof(Open.Data.Persistence.RecordNotFoundException))]
        public void EntityRecordNotFound()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Person person = new Person();
            person.Id = 5;
            person.Select(command);
        }

        [TestMethod]
        public void EntityUpdatePerson()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Person person = new Person();
            person.Id = 1;
            person.Select(command);

            person.FirstNames = "James";
            person.Update(command);

            person = new Person();
            person.Id = 1;
            person.Select(command);

            Assert.AreEqual(person.FirstNames, "James","Record not updated correctly.");
        }

        [TestMethod, ExpectedException(typeof(Open.Data.Persistence.ConcurrencyException))]
        public void EntityConcurrencyException()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Person person = new Person();
            person.Id = 1;
            person.Concurrency = true;
            person.Select(command);

            Person person2 = new Person();
            person2.Id = 1;
            person2.Select(command);
            person2.FirstNames = "Beta";
            person2.Update(command);

            person.FirstNames = "Alpha";
            person.Update(command);
        }

        [TestMethod, ExpectedException(typeof(Open.Data.Persistence.DuplicateKeyException))]
        public void EntityDuplicateKeyException()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Person person = new Person();
            person.Id = 2;
            person.Insert(command);

            Person person2 = new Person();
            person2.Id = 2;
            person2.Insert(command);
        }

        [TestMethod]
        public void EntityDeletePerson()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Person person = new Person();
            person.Id = 4;
            person.Insert(command);

            Person person2 = new Person();
            person2.Id = 4;
            person2.Delete(command);
        }

        [TestMethod]
        public void EntityPersonExists()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Person person = new Person();
            person.Id = 3;
            person.Insert(command);

            person = new Person();
            person.Id = 3;
            Assert.IsTrue(person.Exists(command));
        }

        //Inherited entity tests
        [TestMethod]
        public void EntityCreateCustomer()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Customer customer = new Customer();
            customer.Id = 10;
            customer.CreditLimit = 100;
            customer.Insert(command);
        }

        [TestMethod, ExpectedException(typeof(Open.Data.Persistence.DuplicateKeyException))]
        public void EntityCreateCustomerDuplicateKey()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Customer customer = new Customer();
            customer.Id = 6;
            customer.CreditLimit = 100;
            customer.Insert(command);

            customer = new Customer();
            customer.Id = 6;
            customer.CreditLimit = 100;
            customer.Insert(command);
        }

        [TestMethod]
        public void EntityLoadCustomer()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Customer customer = new Customer();
            customer.Id = 11;
            customer.CreditLimit = 100;
            customer.Insert(command);

            customer = new Customer();
            customer.Id = 11;
            customer.Select(command);

            Assert.IsTrue(customer.Id == 11, "Incorrect customer record loaded.");
        }

        [TestMethod]
        public void EntityUpdateCustomer()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Customer customer = new Customer();
            customer.Id = 12;
            customer.Insert(command);

            customer = new Customer();
            customer.Id = 12;
            customer.Select(command);

            customer.FirstNames = "James";
            customer.CreditLimit = 400;
            customer.CustomerType = CustomerType.Reseller;
            customer.Update(command);

            customer = new Customer();
            customer.Id = 12;
            customer.Select(command);

            Assert.IsTrue(customer.Id == 12, "Incorrect customer record loaded.");
            Assert.AreEqual(customer.FirstNames, "James", "Base record not updated correctly.");
            Assert.AreEqual(customer.CreditLimit, 400M, "Record not updated correctly.");
            Assert.AreEqual(customer.CustomerType, CustomerType.Reseller, "Record not updated correctly.");
        }

        [TestMethod, ExpectedException(typeof(RecordNotFoundException))]
        public void EntityDeleteCustomer()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            //Create a person and a customer
            Customer customer = new Customer();
            customer.Id = 5;
            customer.Insert(command);

            customer = new Customer();
            customer.Id = 5;
            customer.Select(command);

            customer = new Customer();
            customer.Id = 5;
            customer.Delete(command);

            customer = new Customer();
            customer.Id = 5;
            customer.Select(command); //should fail here

        }

        [TestMethod]
        public void EntityObjectPropertyLoadTests()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            ShippingAddress address = new ShippingAddress();
            address.Id = 11;
            address.Line1 = "Line1";
            address.Line2 = "Line2";
            address.Insert(command);

            //Order with address
            Order order = new Order();
            order.Id = 20;
            order.ShippingAddress = address;
            order.Insert(command);

            order = new Order();
            order.Id = 20;
            order.Select(command);

            Assert.IsTrue(order.ShippingAddress != null, "An order was not loaded with an child address.");
            Assert.IsTrue(order.ShippingAddress.Id == 11, "An order was not loaded with a valid child address id.");
            Assert.IsTrue(order.ShippingAddress.Line1 == "Line1" & order.ShippingAddress.Line2 == "Line2", "An order was not loaded with a valid child address details.");

            //Order with no address
            order = new Order();
            order.Id = 21;
            order.ShippingAddress = null;
            order.Insert(command);

            order = new Order();
            order.Id = 21;
            order.Select(command);

            Assert.IsTrue(order.ShippingAddress == null);
        }

        [TestMethod]
        public void EntityObjectPropertySaveTests()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            ShippingAddress address = new ShippingAddress();
            address.Id = 12;
            address.Line1 = "Line1";
            address.Line2 = "Line2";
            address.Insert(command);

            //Order with address
            Order order = new Order();
            order.Id = 22;
            order.ShippingAddress = address;
            order.Insert(command);

            order = new Order();
            order.Id = 22;
            order.Select(command);

            order.TotalWeight = 500;
            order.ShippingAddress.Line1 = "Line1 Updated";
            order.ShippingAddress.Update(command);
            order.Update(command);

            //Load again
            order = new Order();
            order.Id = 22;
            order.Select(command);

            Assert.IsTrue(order.TotalWeight == 500, "Order not saved correctly.");
            Assert.IsTrue(order.ShippingAddress.Line1 == "Line1 Updated", "Address property not updated correctly for order");
        }

        [TestMethod]
        public void EntityStreamTest()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            Note note = new Note();

            note.Id = 1;
            note.Description = "Note";

            Bitmap bitmap = new Bitmap(400, 400);
            Graphics graphic = Graphics.FromImage(bitmap);

            graphic.FillRectangle(new SolidBrush(Color.Blue), 0, 0, 400, 400);
            graphic.Dispose();

            note.Stream = new MemoryStream();
            bitmap.Save(note.Stream, System.Drawing.Imaging.ImageFormat.Bmp);

            note.Insert(command);

            note = new Note();
            note.Id = 1;
            note.Select(command);

            bitmap = new Bitmap(note.Stream);

            Assert.IsTrue(note.Description == "Note", "Note not selected correctly");
            Assert.IsTrue(bitmap.Width == 400 && bitmap.Height == 400, "Note image not selected correctly.");
        }

        [TestMethod]
        public void EntityNullStreamTest()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Note note = new Note();

            note.Id = 2;
            note.Description = "Note 2";
            note.Insert(command);

            note = new Note();
            note.Id = 2;
            note.Select(command);

            Assert.IsTrue(note.Stream == null, "Note stream not null");
        }

        [TestMethod]
        public void EntityStreamNullUpdateTest()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Note note = new Note();

            note.Id = 3;
            note.Description = "Note 3";
            note.Insert(command);

            note = new Note();
            note.Id = 3;
            note.Select(command);

            Bitmap bitmap = new Bitmap(400, 400);
            Graphics graphic = Graphics.FromImage(bitmap);

            graphic.FillRectangle(new SolidBrush(Color.Blue), 0, 0, 400, 400);
            graphic.Dispose();

            note.Stream = new MemoryStream();
            bitmap.Save(note.Stream, System.Drawing.Imaging.ImageFormat.Bmp);
            note.Update(command);

            note = new Note();
            note.Id = 3;
            note.Select(command);

            bitmap = new Bitmap(note.Stream);

            Assert.IsTrue(note.Description == "Note 3", "Note not updated correctly");
            Assert.IsTrue(bitmap.Width == 400 && bitmap.Height == 400, "Note image not selected correctly.");
        }

        [TestMethod]
        public void EntityStreamSizeUpdateTest()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Note note = new Note();

            note.Id = 4;
            note.Description = "Note 4";

            Bitmap bitmap = new Bitmap(400, 400);
            note.Stream = new MemoryStream();
            bitmap.Save(note.Stream, System.Drawing.Imaging.ImageFormat.Bmp);
            note.Insert(command);

            note = new Note();
            note.Id = 4;
            note.Select(command);

            bitmap = new Bitmap(200, 200);
            note.Stream = new MemoryStream();
            bitmap.Save(note.Stream, System.Drawing.Imaging.ImageFormat.Bmp);
            note.Update(command);

            note = new Note();
            note.Id = 4;
            note.Select(command);

            bitmap = new Bitmap(note.Stream);

            Assert.IsTrue(note.Description == "Note 4", "Note not updated correctly");
            Assert.IsTrue(bitmap.Width == 200 && bitmap.Height == 200, "Note image not selected correctly.");
        }

        [TestMethod]
        public void EntityCheckIdentity()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();

            //New records re create becuase they are generated - therefore a duplicate is not raised
            Phone phone = new Phone();
            phone.Number = "555-12345";
            phone.Id = 12345;
            phone.Insert(command);

            phone = new Phone();
            phone.Number = "555-67890";
            phone.Id = 12345;
            phone.Insert(command);
        }

        [TestMethod]
        public void EntityInheritedIdentity()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            International international = new International();
            international.Number = "555-67890";
            international.Insert(command);
        }

        [TestMethod]
        public void EntityCheckOrdinals()
        {
            Command command = Singleton.Instance.GetContext().CreateCommand();
            Order order = new Order();
            Address billing = new Address();
            ShippingAddress shipping = new ShippingAddress();
            Country country = new Country();

            country.Id = 1;
            country.Description = "UK";
            country.Currency = "GBP";
            country.Insert(command);

            billing.Id = 351;
            billing.Line1 = "Billing";
            billing.Country = country;

            shipping.Id = 352;
            shipping.Line1 = "Shipping";
            shipping.Country = country;

            billing.Insert(command);
            shipping.Insert(command);

            order.Id = 350;
            order.BillingAddress = billing;
            order.ShippingAddress = shipping;
            order.Insert(command);

            order = new Order();
            order.Id = 350;
            order.Select(command);

            Assert.IsTrue(order.BillingAddress != null, "Billing address not loaded.");
            Assert.IsTrue(order.ShippingAddress != null, "Shipping address not loaded.");
            Assert.IsTrue(order.BillingAddress.Id == 351, "Billing address loaded incorrectly.");
            Assert.IsTrue(order.ShippingAddress.Id == 352, "Shipping address loaded incorrectly.");
            Assert.IsTrue(order.BillingAddress.Line1 == "Billing", "Billing address loaded incorrectly.");
            Assert.IsTrue(order.ShippingAddress.Line1 == "Shipping", "Shipping address loaded incorrectly.");
        }
    }
}
